﻿using System;

namespace Flagwind.Data
{
	/// <summary>
	/// 以一个输入的字符串，从右向左扫描，得到一个16进制数字的字符串。不区分字符的大小写。
	/// </summary>
	internal class HexUtility
	{
		#region 私有变量

		private string _hexString;
		private string _inputWord = string.Empty;

		#endregion

		#region 私有常量

		private const int Zero = '0';
		private const int AL = 'a';
		private const int AU = 'A';
		private const int KL = 'k';
		private const int KU = 'K';
		private const int QL = 'q';
		private const int QU = 'Q';

		#endregion

		#region 公共属性

		/// <summary>
		/// 获取当前的16进制字符串。
		/// </summary>
		public string Hex
		{
			get
			{
				if(_hexString == null)
				{
					_hexString = MakeHexString();
				}
				return _hexString;
			}
		}

		#endregion

		#region 构造方法

		public HexUtility()
		{
		}

		public HexUtility(string input)
		{
			_inputWord = input;
		}

		#endregion

		#region 公共方法

		/// <summary>
		/// 将1个16进制字符串转换成一个整数
		/// </summary>
		/// <param name="hexString"></param>
		/// <returns></returns>
		public int Hex2Int(string hexString)
		{
			return int.Parse(hexString, System.Globalization.NumberStyles.HexNumber);
		}

		/// <summary>
		/// 构造一个小于0xFFFF 的16进制字符串
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public string MakeHexString(string input)
		{
			_inputWord = input;
			_hexString = null;
			return Hex;
		}

		/// <summary>
		/// 将任意一个字符串转换成65536 以内的整数,方法自身线程安全
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public int String2Int(string input)
		{
			_inputWord = input;
			_hexString = null;
			int[] iArr = new int[4];
			int index = 3;
			for(int i = input.Length - 1; i >= 0; i--)
			{
				char c = input[i];
				int ic = c;
				int temp;
				//如果当前位置不是0，则计算平均数
				if(char.IsDigit(c)) //得到字符型数字对应的数字
				{
					temp = iArr[index] == 0 ? (ic - 48) : (iArr[index] + (ic - 48)) >> 2;
					iArr[index--] = temp;
				}
				else if(char.IsLower(c) && ic < QL) //计算小写字母，得到0xF 以内的数
				{
					temp = iArr[index] == 0 ? (ic - AL) : (iArr[index] + (ic - AL)) >> 2;
					iArr[index--] = temp;
				}
				else if(char.IsUpper(c) && ic < QU) //计算大写写字母，得到0xF 以内的数
				{
					temp = iArr[index] == 0 ? (ic - AU) : (iArr[index] + (ic - AU)) >> 2;
					;
					iArr[index--] = temp;
				}
				if(index < 0)
				{
					index = 3;
				}
			}
			//位移操作，比如 0xf<<4 == 0xf0
			if(iArr[0] > 0)
			{
				iArr[0] <<= 12;
			}
			if(iArr[1] > 0)
			{
				iArr[1] <<= 8;
			}
			if(iArr[2] > 0)
			{
				iArr[2] <<= 4;
			}
			return iArr[0] + iArr[1] + iArr[2] + iArr[3];
		}

		#endregion

		#region 私有方法

		private char GetHexChar(char oldChar, char newChar)
		{
			int oi = Hex2Int(oldChar.ToString());
			int ni = Hex2Int(newChar.ToString());
			int avg = (oi + ni) / 2;
			string str = avg.ToString("x");
			return str[0];
		}

		private void SetHexChar(char[] charArr, ref int charIndex, char newChar)
		{
			char temp = '0';
			if(charArr[charIndex] == '0')
			{
				temp = newChar;
			}
			else
			{
				temp = GetHexChar(charArr[charIndex], newChar);
			}
			charArr[charIndex--] = temp;
		}

		private string MakeHexString()
		{
			char[] charArr =
			{
				'0', '0', '0', '0'
			};
			int charIndex = 3;
			for(int i = _inputWord.Length - 1; i >= 0; i--)
			{
				char c = _inputWord[i];
				if(char.IsDigit(c))
				{
					SetHexChar(charArr, ref charIndex, c);
				}
				else if(char.IsLower(c))
				{
					if(c < 'k')
					{
						SetHexChar(charArr, ref charIndex, (char)(c - AL + Zero));
					}
					else if(c < 'q')
					{
						SetHexChar(charArr, ref charIndex, (char)(c - 10));
					}
				}
				else if(char.IsUpper(c))
				{
					if(c < 'K')
					{
						SetHexChar(charArr, ref charIndex, (char)(c - AU + Zero));
					}
					else if(c < 'Q')
					{
						SetHexChar(charArr, ref charIndex, (char)(c - 10));
					}
				}
				if(charIndex < 0)
				{
					charIndex = 3;
				}
			}
			return new string(charArr);
		}

		#endregion
	}
}